package com.tqz.juc.jmm;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>JMM内存模型可见性测试
 * -Djava.compiler=NONE  JIT即时编译
 *
 * jdk的jre的bin目录下
 *
 * volatile修饰的变量在汇编层面加一个lock前缀，lock前缀又会触发缓存一致性协议，
 * 多个线程操作同一个变量的时候，由总线裁决谁先拿到锁，
 * 没有拿到锁的那个线程就会把自己的变量给丢了，从主内存中拿取最新的值。
 *
 * 缓存行通常只会64字节的大小，如果总线裁决装不下了会放在总线锁里面。
 * 总线裁决效率比较高，所以会先放在总线裁决里面。
 *
 * @author tianqingzhao
 * @since 2022/1/13 21:02
 */
@Slf4j
public class JavaMemoryModelVisibilityTest {
    
    // volatile不保证原子性
    private volatile static boolean initFlag = false;
    
    private volatile static int counter = 0;
    
    public static void refresh() {
        log.info("refresh data.......");
        initFlag = true;
        log.info("refresh data success.......");
    }
    
    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            // 尽管线程B修改了initFlag的值，但线程A的工作内存中的值没有修改，
            // 需要给initFlag加volatile保证变量对其他线程的可见性。
            // 或者输出一句话，或者在while里面操作一个包装类型的变量。
            while (!initFlag) {
                //System.out.println("runing");
                //                counter++;
            }
            log.info("线程：" + Thread.currentThread().getName() + "当前线程嗅探到initFlag的状态的改变");
        }, "threadA");
        threadA.start();
        
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        Thread threadB = new Thread(() -> {
            refresh();
        }, "threadB");
        threadB.start();
    }
    
}
